/*
 *    This file is part of CeluMap.
 *
 *    CeluMap is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    CeluMap is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Copyright 2006, 2007, 2008 Gonzalo Merayo
 *    gonzalo (at) celumap.com.ar
 *    www.celumap.com.ar
 *
 */

package editor;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.filechooser.FileFilter;

import map.MemMap;
import mapWriters.DefaultMapWriter;
import mapWriters.MapWriter;
import panel.MapPanel;
import db.DataSource;
import figures.Figure;
import figures.FigureIterator;
import figures.basic.ImageFigure;
import figures.basic.PoliLine;
import figures.cartography.Street;
import geometry.Point;
import geometry.Rectangle;

public class Editor extends JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1167263098901718377L;
	private MapPanel mapPanel=null;
	private MemMap map = new MemMap();  //  @jve:decl-index=0:
	private int puntoMovido = -1;
	private int radioPuntitos = 5;
	private Figure selectedFigure;
	private MouseListener selectionTool;
	private MouseListener insertionTool;
	private DataSource ds = new DataSource();

	public Editor(){
		super();
	}
	
	public void init(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
		add(getMapPanel());
		showMapBrowser();
		getMapPanel().addKeyListener(new KeyListener(){
			public void keyPressed(KeyEvent e) {
				switch(e.getKeyCode()){
					case KeyEvent.VK_C:
						map = new MemMap();
					case KeyEvent.VK_D:
						if(selectedFigure!=null)
							map.removeFigure(selectedFigure);
						selectedFigure = null;
						repaint();
						break;
					case KeyEvent.VK_N:
						if(selectedFigure!=null)
							new NameDialog(selectedFigure, map, new ActionListener(){
								public void actionPerformed(ActionEvent arg0) {
									repaint();
								}});
						break;
	
					case KeyEvent.VK_A:
						setInsertingTool();
						break;
					case KeyEvent.VK_S:
						save();
						break;
					case KeyEvent.VK_M:
						showMapBrowser();
						break;
					case KeyEvent.VK_R:
						selectRaster();
						break;
					case KeyEvent.VK_P:
						MapWriter b = new DefaultMapWriter();
						FigureIterator i = map.getFigures(null);
						while(i.hasNext())
							b.addFigure(i.next());
						try {
							b.write(new DataOutputStream(new FileOutputStream("l.map")));
						} catch (FileNotFoundException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						} catch (IOException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
						break;
				}
			}
			
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
			}

			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub
			}});
		createTools();
		setSelectionTool();
		setSize(new Dimension(800,800));
	}

	private void showMapBrowser() {
		MapBrowser b = new MapBrowser(this, ds);
		b.setVisible(true);
	}
	
	private void selectRaster() {
		JFileChooser dlg = new JFileChooser();
		dlg.setFileFilter(new FileFilter() {

			@Override
			public boolean accept(File f) {
				if (f.getName().endsWith(".bmp"))
					return true;
				if (f.getName().endsWith(".jpg"))
					return true;
				if (f.getName().endsWith(".png"))
					return true;
				if (f.getName().endsWith(".gif"))
					return true;
				if (f.isDirectory())
					return true;
				return false;
			}

			@Override
			public String getDescription() {
				return "Image Files";
			}

		});
		int returnVal = dlg.showOpenDialog(this);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			loadRaster(dlg.getSelectedFile().getAbsolutePath());
		}
	}
	
	public void loadMap(){
		startProgressBar("Cargando mapa: "+ds.getMapName()+" Version: "+ds.getVersion());
		Thread t = new Thread(new Runnable(){
			public void run() {
				setTitle("Mapa: "+ds.getMapName()+" Version: "+ds.getVersion());
				map.cacheMap(ds.getMap());
				getMapPanel().setMap(map);
				stopProgressBar();
			}});
		t.start();
	}
	
	public void loadRaster(final String bitmap){
		startProgressBar("Cargando raster:"+bitmap);
		Thread t = new Thread(new Runnable(){
			public void run() {
				try {
					getMapPanel().setImap(ImageIO.read(new FileInputStream(bitmap)));
				} catch (FileNotFoundException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				stopProgressBar();
			}});
		t.start();
	}
	
	JDialog progressBar  = null;
	private void startProgressBar(String mensaje){
		progressBar = new JDialog(this, mensaje);
		JProgressBar j = new JProgressBar();
		j.setIndeterminate(true);
		progressBar.add(j);
		progressBar.setSize(new Dimension(350, 50));
		setVisible(false);
		progressBar.setVisible(true);
	}
	private void stopProgressBar(){
		progressBar.setVisible(false);
		setVisible(true);
		progressBar = null;
	}
	
	private void createTools() {
		getMapPanel().setTool(this);
		insertionTool = new MouseAdapter(){
			private Point[] p = null;
			public void mousePressed(MouseEvent arg0){
				p = new Point[2];
				p[0] = new Point(getMapPanel().getTransform().screenX2map(arg0.getX(),arg0.getY()), getMapPanel().getTransform().screenY2map(arg0.getX(),arg0.getY()));
			}
			public void mouseReleased(MouseEvent arg0) {
				p[1] = new Point(getMapPanel().getTransform().screenX2map(arg0.getX(),arg0.getY()), getMapPanel().getTransform().screenY2map(arg0.getX(),arg0.getY()));
				Figure s = new Street(p, "");
				map.appendFigure(s);
				selectedFigure = (PoliLine) s;
				setSelectionTool();
				repaint();
			}
		};
		selectionTool = new MouseListener(){
			public void mouseClicked(MouseEvent arg0) {
				if((arg0.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK)==0){
					int px = getMapPanel().getTransform().screenX2map(arg0.getX(), arg0.getY());
					int py = getMapPanel().getTransform().screenY2map(arg0.getX(), arg0.getY());
					Rectangle area = new Rectangle(0,0,getWidth(), getHeight());
					Rectangle d = new Rectangle();
					getMapPanel().getTransform().screen2map(area, d);
					FigureIterator figs = map.getFigures(d);
					selectedFigure = null;
					double dist = -1;
					while(figs.hasNext()){
						Figure n = figs.next();
						if(n instanceof PoliLine){
							PoliLine p = (PoliLine)n;
							int[] x = p.getx();
							int[] y = p.gety();
							for(int i=0;i<x.length-1;i++){
								double dd = Math.sqrt((x[i]-x[i+1])*(x[i]-x[i+1])+(y[i]-y[i+1])*(y[i]-y[i+1]));
								double da = Math.sqrt((x[i]-px)*(x[i]-px)+(y[i]-py)*(y[i]-py));
								double db = Math.sqrt((x[i+1]-px)*(x[i+1]-px)+(y[i+1]-py)*(y[i+1]-py));
								if(dist == -1 || (da+db-dd)<dist){
									dist = da+db-dd;
									selectedFigure = p;
								}
							}
						}
						if(n instanceof ImageFigure){
							ImageFigure p = (ImageFigure)n;
							double db = Math.sqrt((p.xcenter()-px)*(p.xcenter()-px)+(p.ycenter()-py)*(p.ycenter()-py));
							if(dist == -1 || db<dist){
								dist = db;
								selectedFigure = p;
							}
						}
					}
				}else{
					int px = arg0.getX();
					int py = arg0.getY();
					if(selectedFigure != null){
						if(selectedFigure instanceof PoliLine){
							int puntoABorrar = -1;
							int[] x = ((PoliLine)selectedFigure).getx();
							int[] y = ((PoliLine)selectedFigure).gety();
							for(int i=0;i<x.length;i++){
								if(Math.sqrt(Math.pow((getMapPanel().getTransform().mapX2screen(x[i], y[i])-px),2)+Math.pow((getMapPanel().getTransform().mapY2screen(x[i], y[i])-py),2))<radioPuntitos){
									puntoABorrar = i;
								}
							}
							if(x.length>2){
								int[] xx = new int[x.length-1];
								int[] yy = new int[y.length-1];
								int k=0;
								for(int j=0;j<x.length;j++)
									if(j!=puntoABorrar){
										xx[k] = x[j];
										yy[k++] = y[j];
									}
								((PoliLine)selectedFigure).setxy(xx, yy);
							}
						}
					}
				}
				repaint();
			}

			public void mousePressed(MouseEvent arg0) {
				int px = arg0.getX();
				int py = arg0.getY();
				puntoMovido = -1;
				//origen = null;
				
				if(selectedFigure != null){
					int[] xxx = null;
					int[] yyy = null;
					if(selectedFigure instanceof PoliLine){
						xxx = ((PoliLine)selectedFigure).getx();
						yyy = ((PoliLine)selectedFigure).gety();
					}
					if(selectedFigure instanceof ImageFigure){
						xxx = new int[1];
						yyy = new int[1];
						xxx[0] = ((ImageFigure)selectedFigure).xcenter();
						yyy[0] = ((ImageFigure)selectedFigure).ycenter();
					}
					for(int i=0;i<xxx.length;i++){
						if(Math.sqrt(Math.pow((getMapPanel().getTransform().mapX2screen(xxx[i], yyy[i])-px),2)+Math.pow((getMapPanel().getTransform().mapY2screen(xxx[i], yyy[i])-py),2))<radioPuntitos){
							puntoMovido = i;
						}
					}
					if(puntoMovido==-1){
						//origen = new Point(px, py);
					}
				}
			}

			public void mouseReleased(MouseEvent arg0) {
				int[] xxx = null;
				int[] yyy = null;
				if(selectedFigure instanceof PoliLine){
					xxx = ((PoliLine)selectedFigure).getx();
					yyy = ((PoliLine)selectedFigure).gety();
				}
				if(selectedFigure instanceof ImageFigure){
					xxx = new int[1];
					yyy = new int[1];
					xxx[0] = ((ImageFigure)selectedFigure).xcenter();
					yyy[0] = ((ImageFigure)selectedFigure).ycenter();
				}
				int px=getMapPanel().getTransform().screenX2map(arg0.getX(), arg0.getY());
				int py=getMapPanel().getTransform().screenY2map(arg0.getX(), arg0.getY());
				if(puntoMovido != -1){
					if((arg0.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK)==0){
						if(selectedFigure instanceof PoliLine){
							xxx[puntoMovido]=px;
							yyy[puntoMovido]=py;
							((PoliLine)selectedFigure).setxy(xxx, yyy);
						}
						if(selectedFigure instanceof ImageFigure){
							((ImageFigure)selectedFigure).setPos(px, py);
						}
					}else{
						if(selectedFigure instanceof PoliLine){
							int[] xx = new int[xxx.length+1];
							for(int j=0;j<puntoMovido;j++)
								xx[j] = xxx[j];
							xx[puntoMovido]=px;
							for(int j=puntoMovido;j<xxx.length;j++)
								xx[j+1] = xxx[j];
							
							
							
							int[] yy = new int[yyy.length+1];
							for(int j=0;j<puntoMovido;j++)
								yy[j] = yyy[j];
							yy[puntoMovido]=py;
							for(int j=puntoMovido;j<yyy.length;j++)
								yy[j+1] = yyy[j];
							((PoliLine)selectedFigure).setxy(xx, yy);
						}
					}
				}else{
					//if(origen !=null){
						
					//}
					//origen = null;
				}
				repaint();
			}
			public void mouseEntered(MouseEvent arg0) {}
			public void mouseExited(MouseEvent arg0) {}};
	}
	
	private void save() {
		startProgressBar("Guardando");
		Thread t = new Thread(new Runnable(){
			public void run() {
				ds.write(map);
				stopProgressBar();
			}});
		t.start();
	}
	
	public void setInsertingTool(){
		getMapPanel().removeMouseListener(insertionTool);
		getMapPanel().removeMouseListener(selectionTool);
		getMapPanel().addMouseListener(insertionTool);
	}
		
	public void setSelectionTool(){
		getMapPanel().removeMouseListener(insertionTool);
		getMapPanel().removeMouseListener(selectionTool);
		getMapPanel().addMouseListener(selectionTool);
	}

	public MapPanel getMapPanel() {
		if(mapPanel==null){
			mapPanel = new MapPanel();
			mapPanel.init();
		}
		return mapPanel;
	}
	
	public static void main(String[] args){
		Editor g= new Editor();
		g.init();
	}
	public void toolPaint(Graphics g) {
		if(selectedFigure!=null){
			int[] xxx = null;
			int[] yyy = null;
			if(selectedFigure instanceof PoliLine){
				xxx = ((PoliLine)selectedFigure).getx();
				yyy = ((PoliLine)selectedFigure).gety();
			}
			if(selectedFigure instanceof ImageFigure){
				xxx = new int[1];
				yyy = new int[1];
				xxx[0] = ((ImageFigure)selectedFigure).xcenter();
				yyy[0] = ((ImageFigure)selectedFigure).ycenter();
			}
			for(int i=0;i<xxx.length;i++){
				int px = getMapPanel().getTransform().mapX2screen(xxx[i],yyy[i]);
				int py = getMapPanel().getTransform().mapY2screen(xxx[i],yyy[i]);
				g.setColor(Color.RED);
				g.drawOval(px-radioPuntitos, py-radioPuntitos, radioPuntitos*2, radioPuntitos*2);
			}
		}
	}
}